package com.shiro.shiroConfig;

import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author wangfei
 * @date 2020-11-01 16:52
 * shiro配置
 */
@Configuration
public class ShiroConfig {

    /**
     * 过滤规则
     * 配置一个 ShiroFilterFactoryBean ，在 ShiroFilterFactoryBean 中指定路径拦截规则等。
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        //创建ShiroFilterFactoryBean工厂
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        factoryBean.setSecurityManager(securityManager);
        //没有登录的用户，让其跳转到登录界面
        factoryBean.setLoginUrl("/page/toLogin");

        //控制访问某个资源需要什么权限
        Map map = new LinkedHashMap<>();
        map.put("/page/toLogin","anon"); //访问登录页面 直接放行
        map.put("/","anon"); //访问登录页面 直接放行
        map.put("/user/all","perms[user:select]"); //查询所有用户 需要认证(登录)
        //当用户查看仓库列表时，需要有仓库权限
        map.put("/storage/all","perms[storage:select]");
        //当用户删除用户时，需要有超级管理员角色
//        filterChainMap.put("/user/del/*","roles[role_superman]");
        map.put("/backend/logout","logout");
        //配置的规则放入ShiroFilterFactoryBean工厂中。
        factoryBean.setFilterChainDefinitionMap(map);
        return factoryBean;
    }

    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //把会话管理器交由SecurityManager
        manager.setSessionManager(sessionManager());
        //把Realm交由SecurityManager
        manager.setRealm(myRealm());
        return manager;
    }

    /**
     *realm
     */
    @Bean
    public Realm myRealm(){
        MyRealm myRealm = new MyRealm();
        //告诉realm密码匹配方式【配置自定义密码比较器】
        myRealm.setCredentialsMatcher(credentialsMatcher());

        //缓存AuthorizationInfo[授权]信息的缓存名称
        myRealm.setAuthorizationCacheName("perms");

        //启用授权缓存，即缓存AuthorizationInfo信息[授权]，默认false
        myRealm.setAuthorizationCachingEnabled(true);

        //启用身份验证缓存，即缓存AuthenticationInfo[认证]信息，默认false
        myRealm.setAuthenticationCachingEnabled(false);
        //设置缓存管理器
        myRealm.setCacheManager(cacheManager());

        return myRealm;
    }

    /**
     * 注入加密算法匹配密码时使用
     * @return
     */
    @Bean
    public CredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher hashedMatcher = new HashedCredentialsMatcher();
        hashedMatcher.setHashAlgorithmName("md5");
        //默认加密一次，写不写都行。
        hashedMatcher.setHashIterations(1);
        return hashedMatcher;
    }

    /**
     * 缓存管理
     */

    @Bean
    public CacheManager cacheManager(){
        MyRedisCacheManager cacheManager = new MyRedisCacheManager();
        return cacheManager;
    }

    /**
     * 会话管理器
     * @return
     */
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());

        //设置会话过期时间
        sessionManager.setGlobalSessionTimeout(3*60*1000); //默认半小时
        sessionManager.setDeleteInvalidSessions(true); //默认自定调用SessionDAO的delete方法删除会话
        //设置会话定时检查
        //        sessionManager.setSessionValidationInterval(180000); //默认一小时
        //        sessionManager.setSessionValidationSchedulerEnabled(true);
        return sessionManager;
    }

    @Bean
    public SessionDAO redisSessionDAO(){
        ShiroRedisSessionDao redisDAO = new ShiroRedisSessionDao();
        return redisDAO;
    }

    /**
     * 注解支持
     */
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
